package com.example.sangong.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.sangong.dao.PersonDao;
import com.example.sangong.entity.Person;
import com.example.sangong.entity.PersonExport;
import com.example.sangong.entity.PersonImport;
import com.example.sangong.myenum.DeleteFlagEnum;
import com.example.sangong.myenum.GenderEnum;
import com.example.sangong.rabbitmq.RabbitMqProducer;
import com.example.sangong.req.person.PersonAddReq;
import com.example.sangong.req.person.PersonInfoReq;
import com.example.sangong.req.person.PersonQueryReq;
import com.example.sangong.req.person.PersonUpdateReq;
import com.example.sangong.service.PersonService;
import com.example.sangong.utils.MyStreamUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

@Service
@Slf4j
public class PersonServiceImpl extends ServiceImpl<PersonDao, Person> implements PersonService {

    @Resource
    private PersonDao personDao;
    @Resource
    private RabbitMqProducer rabbitMqProducer;

    @Override
    public Person selectPersonById(PersonInfoReq req) {
        return personDao.selectPersonById(req.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addPerson(PersonAddReq req) {
        //验证名称唯一性
        validateNameUnique(req.getName(), null);
        Person person = new Person();
        BeanUtils.copyProperties(req, person);
        person.setCreateTime(LocalDateTime.now());
        person.setUpdateTime(person.getCreateTime());
        personDao.insert(person);
        rabbitMqProducer.send(person);
    }

    private void validateNameUnique(String name, Long id) {
        LambdaQueryWrapper<Person> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Person::getName, name);
        if (Objects.nonNull(id)) {
            queryWrapper.ne(Person::getId, id);
        }
        queryWrapper.select(Person::getName);
        queryWrapper.eq(Person::getDeleteFlag, DeleteFlagEnum.EFFECTIVE.getCode());
        List<Person> personList = personDao.selectList(queryWrapper);
        if (CollectionUtil.isNotEmpty(personList)) {
            String nameList = String.join(",", MyStreamUtils.cosList(personList, Person::getName)) + "名称已被使用！";
            throw new RuntimeException(nameList);
        }
    }

    private void validateNamesUnique(List<String> names) {
        validateExcelData(names);
        validateDbData(names);
    }

    private void validateDbData(List<String> names) {
        LambdaQueryWrapper<Person> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Person::getName, names);
        queryWrapper.select(Person::getName);
        queryWrapper.eq(Person::getDeleteFlag, DeleteFlagEnum.EFFECTIVE.getCode());
        List<Person> personList = personDao.selectList(queryWrapper);

        if (CollectionUtil.isNotEmpty(personList)) {
            Set<Object> nameSet = MyStreamUtils.cosSet(personList, Person::getName);
            StringBuilder errorMsg = new StringBuilder();
            for (int i = 0; i < names.size(); i++) {
                String name = names.get(i);
                if (nameSet.contains(name)) {
                    errorMsg.append(String.format("第%d行名称(%s)在已被使用了", i + 1, name)).append("\r\n");
                }
            }
            throw new RuntimeException(errorMsg.toString());
        }
    }

    private static void validateExcelData(List<String> names) {
        StringBuilder errorMsg = new StringBuilder();
        Set<String> nameSet = new HashSet<>();
        for (int i = 0; i < names.size(); i++) {
            String name = names.get(i);
            if (!nameSet.add(name)) {
                errorMsg.append(String.format("第%d行名称(%s)在导入的数据列表中已存在", i + 1, name)).append("\r\n");
            }
        }
        if (errorMsg.length() > 0) {
            throw new RuntimeException(errorMsg.toString());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePerson(PersonUpdateReq req) {
        validateNameUnique(req.getName(), req.getId());
        Person person = new Person();
        BeanUtils.copyProperties(req, person);
        person.setUpdateTime(LocalDateTime.now());
        personDao.updateById(person);
        rabbitMqProducer.send(person);
    }

    @Override
    public List<Person> selectByName(PersonQueryReq req) {
        LambdaQueryWrapper<Person> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(Person::getName, req.getName());
        queryWrapper.eq(Person::getDeleteFlag, DeleteFlagEnum.EFFECTIVE.getCode());
        return personDao.selectList(queryWrapper);
    }

    @Override
    public Boolean deleteById(Long id) {
        LambdaQueryWrapper<Person> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Person::getId, id);
        Person update = new Person();
        update.setId(id);
        update.setDeleteFlag(DeleteFlagEnum.DELETED.getCode());
        personDao.update(update, queryWrapper);
        rabbitMqProducer.send(update);
        return Boolean.TRUE;
    }

    @Override
    public IPage<Person> getUserPage(PersonQueryReq req) {
        log.info("真实执行方法的线程id:{}", Thread.currentThread().getId());

        // 创建分页对象
        Page<Person> page = new Page<>(req.getPageNum(), req.getPageSize());
        LambdaQueryWrapper<Person> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(req.getName())) {
            queryWrapper.like(Person::getName, req.getName());
        }
        queryWrapper.eq(Person::getDeleteFlag, DeleteFlagEnum.EFFECTIVE.getCode());
        queryWrapper.orderByDesc(Person::getUpdateTime);
        queryWrapper.orderByAsc(Person::getName, Person::getAge);
        // 调用 Mapper 方法进行分页查询
        return personDao.selectPage(page, queryWrapper);
    }

    @Override
    public IPage<Person> selectPageCustom(PersonQueryReq req) {
        // 创建分页对象
        Page<Person> page = new Page<>(req.getPageNum(), req.getPageSize());
        // 调用 Mapper 方法进行分页查询
        return personDao.selectPageCustom(page, req.getName());
    }

    @Override
    public List<PersonExport> getExportPersonList(String name) {
        LambdaQueryWrapper<Person> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(name)) {
            queryWrapper.like(Person::getName, name);
        }
        queryWrapper.eq(Person::getDeleteFlag, DeleteFlagEnum.EFFECTIVE.getCode());
        queryWrapper.orderByDesc(Person::getUpdateTime);
        queryWrapper.orderByAsc(Person::getName, Person::getAge);
        List<Person> personList = personDao.selectList(queryWrapper);
        List<PersonExport> personExports = MyStreamUtils.cosList(personList, e -> {
            PersonExport export = new PersonExport();
            BeanUtils.copyProperties(e, export);
            export.setGender(GenderEnum.convert(e.getGender()));
            return export;
        });
        return personExports;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer importData(List<PersonImport> personImports) {
        if (CollectionUtil.isEmpty(personImports)) {
            throw new RuntimeException("导入的数据为空");
        }
        validateNamesUnique(MyStreamUtils.cosList(personImports, PersonImport::getName));
        List<Person> personList = MyStreamUtils.cosList(personImports, e -> {
            Person person = new Person();
            BeanUtils.copyProperties(e, person);
            person.setId(IdUtil.getSnowflake().nextId());
            person.setCreateTime(LocalDateTime.now());
            person.setUpdateTime(person.getCreateTime());
            person.setGender(GenderEnum.getVal(e.getGender()));
            person.setDeleteFlag(DeleteFlagEnum.EFFECTIVE.getCode());
            return person;
        });
        this.saveBatch(personList);
        rabbitMqProducer.sendList(personList);
        return personList.size();
    }
}
